﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Globalization;
using System.Collections;

//using CochinitaCorte.CochinitaCorteData;

namespace CochinitaCorte//.BusinessLayer
{
    public class BusinessLayer 
    {
        IFormatProvider culture = new CultureInfo("es-MX", true);
     	
        private Parameters Parametros;

        private List<Users> users;
 
        private DataLayer _DataLayer;

        private readonly string BoldOn = "\x1B\x45\x01";

        private readonly string BoldOff = "\x1B\x45\x02";

        private List<CutSales> CT;
       
        private List<CutSales> CTCompleto;
     
        public BusinessLayer(bool Load=true)
        {
            this._DataLayer = new DataLayer();

            if (Load)
              Initialization();
            
        }

        #region PublicMethods

        public void RefreshParameters()
        {
            Initialization();
        }

        public bool ExportUsers()
        {
            string path = Environment.CurrentDirectory;
            try
            {
                var usersExported = (from n in users
                                     select new
                                     {
                                         ID = n.ID,
                                         NAME = n.Nombre,
                                         DESCRIPTION = (n.Permisos == "62" ? "Adminsitrador" : "Cajero"),
                                         USER = n.Usuario,
                                         PASSWORD = n.Contrasena,
                                         RIGHTS = n.Permisos
                                     }).ToList();

                FileManager.CreateCSVFile(path, usersExported);
            }
            catch
            {
                return false;
           }
            return true;
        }

        public bool UpdateUserData(Users user)
        {
            List<string> SQL = new List<string>();

            ///////////////////////////////////////////////////
            CustomSQL nn = new CustomSQL();

            nn.Clause = CustomSQL.Clauses.Update;
            nn.Table = "Usuarios";
            nn.Where = true;
            nn.WhereFieldName = "ID";
            nn.WhereValue = user.ID;

            ////////////////////////////////////////////////////

            nn.Columns.Add(AddValues("ID", user.ID));
            nn.Columns.Add(AddValues("Nombre", user.Nombre));
            nn.Columns.Add(AddValues("Usuario", user.Usuario));
            nn.Columns.Add(AddValues("Contrasena", user.Contrasena));
            nn.Columns.Add(AddValues("Permisos", user.Permisos));
            SQL.Add(nn.ProcessSQL());

           
            if (this._DataLayer.SetData(SQL))
            {
                users.Remove(users.Where(n => n.ID.Equals(user.ID)).Select(c => c).FirstOrDefault());
                users.Add(user);
                return true;
            }

            return false;

        }

        public bool DeleteUserData(int ID)
        {
            List<string> SQL = new List<string>();

            ///////////////////////////////////////////////////
            CustomSQL nn = new CustomSQL();

            nn.Clause = CustomSQL.Clauses.Delete;
            nn.Table = "Usuarios";
            nn.Where = true;
            nn.WhereFieldName = "ID";
            nn.WhereValue = ID;

            ////////////////////////////////////////////////////

            SQL.Add(nn.ProcessSQL());

            if (this._DataLayer.SetData(SQL))
            {
                users.Remove(users.Where(n => n.ID.Equals(ID)).Select(c => c).FirstOrDefault());
                return true;
            }

            return false;
        }
        
        public bool AddUserData(Users NewUser)
        {
            List<string> SQL = new List<string>();

            ///////////////////////////////////////////////////
            CustomSQL nn = new CustomSQL();

            nn.Clause = CustomSQL.Clauses.Insert;
            nn.Table = "Usuarios";
            nn.Where = false;
           
            ////////////////////////////////////////////////////

            nn.Columns.Add(AddValues("ID", NewUser.ID));
            nn.Columns.Add(AddValues("Nombre", NewUser.Nombre));
            nn.Columns.Add(AddValues("Usuario", NewUser.Usuario));
            nn.Columns.Add(AddValues("Contrasena", NewUser.Contrasena));
            nn.Columns.Add(AddValues("Permisos", NewUser.Permisos));

            SQL.Add(nn.ProcessSQL());

            if (this._DataLayer.SetData(SQL))
            {
                users.Add(NewUser);
                return true;
            }

            return false;
        }

        public bool SetFiscalDataForm(FiscalData FD, DailyGoals DG)
        {
            List<string> SQL = new List<string>();
            
            ///////////////////////////////////////////////////
            CustomSQL nn = new CustomSQL();
                              
            nn.Clause =  CustomSQL.Clauses.Update;
            nn.Table = "Franquicias";
            nn.Where = true;
            nn.WhereFieldName = "CodigoRest";
            nn.WhereValue = FD.Franquicia;
            
            ////////////////////////////////////////////////////

                 nn.Columns.Add(AddValues("CodigoRest", FD.Franquicia));
                 nn.Columns.Add(AddValues("Nombre",FD.Nombre));
                 nn.Columns.Add(AddValues("NombreFiscal",FD.NombreFiscal));  
                 nn.Columns.Add(AddValues("RFC",FD.RFC));
                 nn.Columns.Add(AddValues("Direccion",FD.Direccion));  
                 nn.Columns.Add(AddValues("Ciudad",FD.Ciudad));
                 nn.Columns.Add(AddValues("Telefono",FD.Telefono));
                 nn.Columns.Add(AddValues("InicioOperaciones",FD.InicioOperaciones.Day.ToString("00") + "/" + FD.InicioOperaciones.Month.ToString("00") + "/" + FD.InicioOperaciones.Year.ToString("0000")));
                 nn.Columns.Add(AddValues("PagaIVA", FD.PagaIVA));

                 SQL.Add(nn.ProcessSQL());

            ////////////////////////////////////////////////////
                
                 nn.Table = "Limites";
                 nn.Columns.Clear();
                  
                 nn.Columns.Add(AddValues("CodigoRest",DG.Franquicia));  
                 nn.Columns.Add(AddValues("Lunes",DG.Lunes));    
                 nn.Columns.Add(AddValues("Martes",DG.Martes));    
                 nn.Columns.Add(AddValues("Miercoles",DG.Miercoles));    
                 nn.Columns.Add(AddValues("Jueves",DG.Jueves));    
                 nn.Columns.Add(AddValues("Viernes",DG.Viernes));    
                 nn.Columns.Add(AddValues("Sabado",DG.Sabado));    
                 nn.Columns.Add(AddValues("Domingo",DG.Domingo));    
 
                 SQL.Add(nn.ProcessSQL());

                 return this._DataLayer.SetData(SQL);
               
        }

        public bool SetSettings(Settings value)
        {
             List<string> SQL = new List<string>();
            
            
            CustomSQL nn = new CustomSQL();
                              
            nn.Clause =  CustomSQL.Clauses.Update;
            nn.Table = "Settings";
            nn.Where = false;

            //nn.Columns.Add(AddValues("IVA", value.IVA));
            nn.Columns.Add(AddValues("Impresora",value.PrinterName));
            //nn.Columns.Add(AddValues("FTPSettings", value.ftpParams));
            //nn.Columns.Add(AddValues("PaginaWeb", value.PaginaWeb));
            //nn.Columns.Add(AddValues("GuardarZ", value.GuardarZ));

            SQL.Add(nn.ProcessSQL());

            return this._DataLayer.SetData(SQL);
        }

        private SimpleDatabaseValues AddValues(string Field, object value)
        {
            SimpleDatabaseValues col = new SimpleDatabaseValues();

            col.parameter = Field;
            col.value = value;

            return col;
        }
        
        public object GetFranquicias()
        {
            return Parametros.DatosFiscales.Select(n => n.Nombre).ToList();
        }

        public object GetFiscalData(string franquiciaName)
        {
            return  (from n in Parametros.DatosFiscales
                       where n.Nombre == franquiciaName
                       select n).FirstOrDefault();
        }

        public int GetMaxUserID()
        {
            return  users.Max(n => n.ID) + 1;
        }

        public IEnumerable<object> GetUserInfo(string UserName, int ID = 0)
        {
           // object results;

            if (UserName == string.Empty)
                return   users.Where(n => n.ID == ID).Select(n => n);
            else
                return   users.Where(n => n.Usuario.ToUpper() == UserName.ToUpper()).Select(n => n);

           // return results;
        }
 
        public object GetMetas(string franquiciaName)
        {
            var franquiciaID = (from n in Parametros.DatosFiscales
                                where n.Nombre == franquiciaName
                                select n.Franquicia).FirstOrDefault();

            return  (from n in Parametros.MetasDiarias
                    where n.Franquicia == franquiciaID
                     select n).FirstOrDefault();
        }
       
        public object GetSettings()
        {
            return Parametros.settings;
        }

        public DataTable Process(DateTime From, DateTime To, List<string> FranquiciasSelected, bool IsFTP) //DataTable return
        {
            this.Parametros.StartDate = From;
            this.Parametros.EndDate = To;
            this.Parametros.AuditType = (IsFTP ? 1 : 2);
            this.Parametros.FranquiciasSeleccionadas = (from n in this.Parametros.DatosFiscales
                                                       where FranquiciasSelected.Contains(n.Nombre)
                                                       select n.Franquicia).ToList();
              
            
            this.Parametros.settings.ftpParams.downloadPath = "Cargas";
            
            Cortes results = new Cortes(Parametros);

            CT = results.CorteVentas;
            CTCompleto = results.CorteVentas;
            //FILTRO

            return FillGrid(Algorithm()); ;
          
        }
        public int PrintCorteComplete()
        {
            PrinterManager PM = new PrinterManager(Parametros.settings.PrinterName);
   
            try
            {

                foreach (var Ticket in CTCompleto.Where(n => n.tickets.Count > 0))
                {
                    int NumFolio = 1;

                    PM.EncabezadoVenta("C O R T E\n");

                    PM.EncabezadoVenta(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")) + "\n");

                    foreach (var Folios in Ticket.tickets)
                    {
                        //FOLIO
                        PM.EncabezadoVenta("FOLIO   : " + NumFolio + "\n\n"); // imprime encabezados FOLIO

                        //ALIMENTOS, BEBIDAS, EXTRAS, 
                        PM.AgregaArticulo(Folios.Alimentos.ToString("#,##0.00"), Folios.Bebidas.ToString("#,##0.00"), Folios.Extra.ToString("#,##0.00"));

                        //SUBTOTAL, IVA, TOTAL
                        PM.AgregaTotales(Folios.SubTotal.ToString("#,##0.00"), Folios.Iva.ToString("#,##0.00"), Folios.Total.ToString("#,##0.00"));

                        NumFolio++;
                    }
                    PM.SaltoDeLinea();
                    PM.SaltoDeLinea();

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.NombreFiscal).FirstOrDefault());

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.RFC).FirstOrDefault());

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Direccion).FirstOrDefault());

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Ciudad).FirstOrDefault());

                    PM.TextoCentro("Tel: " + Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Telefono).FirstOrDefault());

                    PM.TextoCentro(Parametros.settings.PaginaWeb);

                    PM.SaltoDeLinea();

                    PM.TextoCentro(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")));

                    PM.TextoCentro("Franquicia " + Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Nombre).FirstOrDefault() + "\n\n");

                    PM.AgregaArticulo(Ticket.Alimentos.ToString("#,##0.00"), Ticket.Bebidas.ToString("#,##0.00"), Ticket.Extra.ToString("#,##0.00"));

                    PM.AgregaTotales(Ticket.SubTotal.ToString("#,##0.00"), Ticket.Iva.ToString("#,##0.00"), Ticket.Total.ToString("#,##0.00")); // imprime linea con total

                    PM.ImprimeFolioZ("");

                    PM.CortaTicket();
                }

            }
            catch (Exception ex)
            {
                return 0;
            }
            return 1;
        }
  
        public int PrintCorteN()
        {
            PrinterManager PM = new PrinterManager(Parametros.settings.PrinterName); 

          try{

               foreach (var Ticket in CT.Where(n => n.tickets.Count > 0))
                {
                        int NumFolio = 1;

                        PM.EncabezadoVenta("C O R T E\n");

                        PM.EncabezadoVenta(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")) + "\n");

                        foreach (var Folios in Ticket.tickets)
                        {
                            //FOLIO
                            PM.EncabezadoVenta("FOLIO   : " + NumFolio + "\n\n"); // imprime encabezados FOLIO

                            //ALIMENTOS, BEBIDAS, EXTRAS, 
                            PM.AgregaArticulo(Folios.Alimentos.ToString("#,##0.00"), Folios.Bebidas.ToString("#,##0.00"), Folios.Extra.ToString("#,##0.00")); 

                            //SUBTOTAL, IVA, TOTAL
                            PM.AgregaTotales(Folios.SubTotal.ToString("#,##0.00"), Folios.Iva.ToString("#,##0.00"), Folios.Total.ToString("#,##0.00")); 

                            NumFolio++;
                        }
                        PM.SaltoDeLinea();
                        PM.SaltoDeLinea();

                        PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.NombreFiscal).FirstOrDefault());

                        PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.RFC).FirstOrDefault());

                        PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Direccion).FirstOrDefault());

                        PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Ciudad).FirstOrDefault());

                        PM.TextoCentro("Tel: " + Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Telefono).FirstOrDefault());

                        PM.TextoCentro(Parametros.settings.PaginaWeb);

                        PM.SaltoDeLinea();

                        PM.TextoCentro(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")));

                        PM.TextoCentro("Franquicia " + Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Nombre).FirstOrDefault() + "\n\n");

                        PM.AgregaArticulo(Ticket.Alimentos.ToString("#,##0.00"), Ticket.Bebidas.ToString("#,##0.00"), Ticket.Extra.ToString("#,##0.00")); 

                        PM.AgregaTotales(Ticket.SubTotal.ToString("#,##0.00"), Ticket.Iva.ToString("#,##0.00"), Ticket.Total.ToString("#,##0.00")); // imprime linea con total

                        PM.ImprimeFolioZ("");

                        PM.CortaTicket();
               }
                    
          }
          catch(Exception ex){
                return 0;     
          }
           return 1;
        }

        public int PrintCorteZ()
        {
            PrinterManager PM = new PrinterManager(Parametros.settings.PrinterName); 

             try{

               foreach (var Ticket in CT.Where(n => n.tickets.Count > 0))
                {
                    int CodigoZ = 0;
                    int NumFolio = 1;

                    DateTime FechaInicial = Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.InicioOperaciones).FirstOrDefault(); // DateTime.ParseExact("01/01/2008", "dd/MM/yyyy", culture);
                    DateTime HOY = Ticket.Fecha;

                    CodigoZ = (HOY.Subtract(FechaInicial).Days) + 1;

                    PM.TextoCentro("C O R T E   Z   #  " + (Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Nombre).FirstOrDefault() == "CUCHILLA" ? "A" : "") + CodigoZ + "\n\n");

                    PM.EncabezadoVenta(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")) + "\n");

                    foreach (var Folios in Ticket.tickets)
                    {
                        //FOLIO
                        PM.EncabezadoVenta("\n\nFOLIO   : " + NumFolio + "\n\n"); // imprime encabezados FOLIO

                        string Texto = "";

                        foreach (var tt in Folios.DetalleVentas)
                            if (tt.PrecioTotal != 0) Texto += PM.AgregaArticuloDetallado(tt.CantidadArticulos + " " + tt.NombreArticulo, tt.PrecioTotal.ToString("#,##0.00"));

                      //  PM.ImprimeFolioZ(Texto);

                        //SUBTOTAL, IVA, TOTAL
                        PM.AgregaTotales(Folios.SubTotal.ToString("#,##0.00"), Folios.Iva.ToString("#,##0.00"), Folios.Total.ToString("#,##0.00")); // imprime linea con total

                        NumFolio++;
                    }
                    PM.SaltoDeLinea();
                    PM.SaltoDeLinea();

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.NombreFiscal).FirstOrDefault());

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.RFC).FirstOrDefault());

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Direccion).FirstOrDefault());

                    PM.TextoCentro(Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Ciudad).FirstOrDefault());

                    PM.TextoCentro("Tel: " + Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Telefono).FirstOrDefault());

                    PM.TextoCentro(Parametros.settings.PaginaWeb);

                    PM.SaltoDeLinea();

                    PM.TextoCentro(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")));

                    PM.TextoCentro("Franquicia " + Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Nombre).FirstOrDefault() + "\n\n");

                    PM.AgregaArticulo(Ticket.Alimentos.ToString("#,##0.00"), Ticket.Bebidas.ToString("#,##0.00"), Ticket.Extra.ToString("#,##0.00"));  

                    PM.AgregaTotales(Ticket.SubTotal.ToString("#,##0.00"), Ticket.Iva.ToString("#,##0.00"), Ticket.Total.ToString("#,##0.00"));

                    PM.ImprimeFolioZ("");
                    PM.CortaTicket();

                  // CreateAuditFile(Ticket);
                    
               }
                    
          }
          catch(Exception ex){
                return 0;     
          }
           return 1;
        }

        public int PrintCorteC()
        {
            PrinterManager PM = new PrinterManager(Parametros.settings.PrinterName);

            try
            {
                foreach (var Ticket in CTCompleto.Where(n => n.tickets.Count > 0))
                {

                    PM.TextoCentro(BoldOn + (Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Nombre).FirstOrDefault()) + BoldOff);

                    PM.TextoCentro((Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.RFC).FirstOrDefault()));

                    PM.TextoCentro((Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Direccion).FirstOrDefault()));

                    PM.TextoCentro((Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Ciudad).FirstOrDefault()));

                    PM.TextoCentro("TEL " + (Parametros.DatosFiscales.Where(n => n.Franquicia == Ticket.Franquicia).Select(n => n.Telefono).FirstOrDefault()));

                    PM.EncabezadoVenta(Ticket.Fecha.ToString("D", new CultureInfo("es-ES")) + "\n\n");


                    PM.TextoIzquierda(BoldOn + "TOTAL DE COBRO" + BoldOff);
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////
                    PM.TextoExtremos("TOTAL", Ticket.Total.ToString("#,#00.00"));
                    PM.EncabezadoVenta("\n");
                    PM.TextoIzquierda("COBRO POR CAJERO\n");
                    PM.TextoExtremos("CAJERO", "TOTAL");

                    //loop cajeros
                    var cajeros = from s in Ticket.tickets.Select(d => d.DetalleVentas).Select(o => o.Select(h => new { h.Cajero, h.PrecioTotal })).ToList()
                                  from r in s.Select(i => new { i.Cajero, i.PrecioTotal })
                                  group r by r.Cajero into g
                                  select new { CajeroID = g.Key, totalVendido = g.Sum(j => j.PrecioTotal) };

                    foreach (var test in cajeros)
                    {
                        string NombreCajero = users.Where(w => w.Usuario == test.CajeroID).Select(n => n.Nombre).FirstOrDefault();
                        PM.TextoExtremos(NombreCajero , test.totalVendido.ToString("#,#00.00"));
                    }
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////
                    PM.TextoIzquierda(BoldOn + "TOTAL DE COBRO CON TARJETA" + BoldOff);
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////


                    var tarjeta = from s in Ticket.tickets//.Where(c => c.Tarjeta > 0).DefaultIfEmpty() 
                                  from ss in s.DetalleVentas.Select(h => new { h.Cajero, s.Tarjeta }).ToList()
                                  group ss by ss.Cajero into g
                                  select new { CajeroID = g.Key, totalEnTarjeta = g.Sum(j => j.Tarjeta) };

                    PM.TextoExtremos("TOTAL", tarjeta.Sum(sum => sum.totalEnTarjeta).ToString("#,#00.00"));
                    PM.TextoIzquierda("COBRO POR CAJERO\n");
                    PM.TextoExtremos("CAJERO", "TOTAL");
                    //loop cajeros


                    foreach (var test in tarjeta)
                    {
                        string NombreCajero = users.Where(w => w.Usuario == test.CajeroID).Select(n => n.Nombre).FirstOrDefault();
                        PM.TextoExtremos(NombreCajero, test.totalEnTarjeta.ToString("#,#00.00"));
                    }
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////
                    PM.TextoIzquierda(BoldOn + "TOTAL COBRADO CON DOLARES(EN PESOS)" + BoldOff);
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////
                    var detallesDolaresPesos = Ticket.tickets.SelectMany
                                          (s => s.DetalleVentas.Select
                                                                     (h => new 
                                                                     { 
                                                                       Folio = h.Folio, 
                                                                       s.Efectivo ,
                                                                       Cajero = h.Cajero, 
                                                                       Dolares = s.Dolares,
                                                                       TotalDolares = ((s.Dolares * s.TipoCambio) > s.Total ? s.Total : (s.Dolares * s.TipoCambio)), 
                                                                       TipoCambio = s.TipoCambio,
                                                                       TotalPesos = (s.Total - (s.Efectivo > s.Total ? 0 : ((s.Dolares * s.TipoCambio) > s.Total ? s.Total : (s.Dolares * s.TipoCambio))))
                                                                      })
                                           ).Distinct()
                                            .ToList()
                                            .GroupBy(i => i.Cajero)
                                            .Select(all => new 
                                            {
                                              Cajero = all .Key,
                                              TotalDolares =  all.Sum(item => item.TotalDolares),
                                              TotalPesos = all.Sum(item => item.TotalPesos),
                                              TipoCambio = all.Select(item => item.TipoCambio).FirstOrDefault(),
                                            });
                   
                   decimal exchangeRate = detallesDolaresPesos.Select(t => t.TipoCambio).FirstOrDefault();

                    PM.TextoExtremos("TOTAL", exchangeRate.ToString("#,#00.00") + "  " + (detallesDolaresPesos.Sum(sum => sum.TotalDolares)).ToString("#,#00.00"));
                    PM.TextoIzquierda("COBRO POR CAJERO\n");
                    PM.TextoExtremos("CAJERO", "TOTAL");
                    //loop cajeros

                    foreach (var test in detallesDolaresPesos)
                    {
                        string NombreCajero = users.Where(w => w.Usuario == test.Cajero).Select(n => n.Nombre).FirstOrDefault();
                        PM.TextoExtremos(NombreCajero, test.TipoCambio.ToString("#,#00.00") + "  " + test.TotalDolares.ToString("#,#00.00"));
                    }
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////
                    PM.TextoIzquierda(BoldOn + "TOTAL DE COBRADO CON PESOS" + BoldOff);
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    /////////////////////////////////////////////////////////////// PENDIENTE
                                    
                    PM.TextoExtremos("TOTAL", detallesDolaresPesos.Sum( g => g.TotalPesos).ToString("#,#00.00"));
                    PM.TextoIzquierda("COBRO POR CAJERO\n");
                    PM.TextoExtremos("CAJERO", "TOTAL");
                    //loop cajeros
                    foreach (var test in detallesDolaresPesos)
                    {
                        string NombreCajero = users.Where(w => w.Usuario == test.Cajero).Select(n => n.Nombre).FirstOrDefault();
                        PM.TextoExtremos(NombreCajero, test.TotalPesos.ToString("#,#00.00"));
                    }
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////
                    PM.TextoIzquierda(BoldOn + "MONTO FACTURADO" + BoldOff);
                    ///////////////////////////////////////////////////////////////
                    PM.LineasGuion();
                    PM.LineasGuion();
                    ///////////////////////////////////////////////////////////////

                    var facturado = from s in Ticket.tickets
                                    from ss in s.DetalleVentas.Select(h => new { h.Cajero, s.Total, s.Facturado }).ToList()
                                    group ss by ss.Cajero into g
                                    select new { CajeroID = g.Key, totalFacturado = g.Where(w => w.Facturado == true).Sum(j => j.Total) };

                    PM.TextoExtremos("TOTAL", facturado.Sum(s => s.totalFacturado).ToString("#,#00.00"));
                    PM.TextoIzquierda("FACTURADO POR CAJERO\n");
                    PM.TextoExtremos("CAJERO", "TOTAL");
                    //loop cajeros

                    foreach (var test in facturado)
                    {
                        string NombreCajero = users.Where(w => w.Usuario == test.CajeroID).Select(n => n.Nombre).FirstOrDefault();
                        PM.TextoExtremos(NombreCajero, test.totalFacturado.ToString("#,#00.00"));
                    }
                    PM.ImprimeFolioZ("");
                    PM.CortaTicket();
                }

            }
            catch (Exception ex)
            {
                return 0;
            }
            return 1;
        }

        #endregion 

        #region privateMethods
        private void Initialization()
        {
          InitialShop init = new InitialShop();
          InitialProcess initBuilder;
          initBuilder = new InitialLoader();
          init.LoadInitialData(initBuilder);
          Parametros = initBuilder.parametros;
          users = initBuilder.usuarios;
        }

        private DataTable FillGrid(List<CutSales> Cortes)
         {
          DataTable dt = new DataTable("Corte");

          dt.Columns.Add("Franquicia");
          dt.Columns.Add("Fecha");
          dt.Columns.Add("Alimentos");
          dt.Columns.Add("Bebidas");
          dt.Columns.Add("Extras");
          dt.Columns.Add("Subtotal");
          dt.Columns.Add("IVA");
          dt.Columns.Add("Total");
          dt.Columns.Add("Meta Diaria");
          dt.Columns.Add("Cant. Folios");

         
              foreach (var corte in Cortes)
              {

                  if (corte.tickets.Count != 0 && corte.Total != 0)
                  {
                      DataRow row = dt.NewRow();
                      row["Franquicia"] = Parametros.DatosFiscales.Where(n => n.Franquicia == corte.Franquicia).Select(n => n.Nombre).FirstOrDefault();
                      row["Fecha"] = corte.Fecha.ToShortDateString();
                      row["Alimentos"] = corte.Alimentos.ToString("0.00");
                      row["Bebidas"] = corte.Bebidas.ToString("0.00");
                      row["Extras"] = corte.Extra.ToString("0.00");
                      row["Subtotal"] = corte.SubTotal.ToString("0.00");
                      row["IVA"] = corte.Iva.ToString("0.00");
                      row["Total"] = corte.Total.ToString("0.00");
                      row["Meta Diaria"] = corte.Meta;
                      row["Cant. Folios"] = corte.tickets.Count;
                      dt.Rows.Add(row);
                      dt.AcceptChanges();
                  }
                  else
                  {
                      DataRow row = dt.NewRow();
                      row["Franquicia"] = Parametros.DatosFiscales.Where(n => n.Franquicia == corte.Franquicia).Select(n => n.Nombre).FirstOrDefault();
                      row["Fecha"] = corte.Fecha.ToShortDateString();
                      row["Alimentos"] = "No Disponible";
                      row["Bebidas"] = "No Disponible";
                      row["Extras"] = "No Disponible";
                      row["Subtotal"] = "No Disponible";
                      row["IVA"] = "No Disponible";
                      row["Total"] = "No Disponible";
                      row["Meta Diaria"] = "No Disponible";
                      row["Cant. Folios"] = "No Disponible";
                      dt.Rows.Add(row);
                      dt.AcceptChanges();
                  }
              }

          return dt; 
            
      }
    
        private IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
        {
              for (var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
                  yield return day;
         }

        private List<CutSales> Algorithm()
        {
            List<CutSales> cortes = new List<CutSales>();

            foreach (var corte in CT) //CT.Where(n => n.Total > 0)
            {
               List<SalesMaster> SM = new List<SalesMaster>();

               VentasObligadas(corte.tickets, ref SM);
               VentasDeRelleno(corte.tickets, ref SM,corte.Meta);

               cortes.Add(
                            new CutSales
                            {
                                NumCorte = corte.NumCorte,
                                Fecha = corte.Fecha,
                                Meta = corte.Meta,
                                Franquicia = corte.Franquicia,
                                Alimentos = SM.Sum(n => n.Alimentos),
                                Bebidas = SM.Sum(n => n.Bebidas),
                                Extra = SM.Sum(n => n.Extra),
                                SubTotal = SM.Sum(n => n.SubTotal),
                                Iva = SM.Sum(n => n.Iva),
                                Total = SM.Sum(n => n.Total),
                                tickets = SM
                            }
                         );

            }

            CT = cortes;
            return cortes;
        }

        private void VentasObligadas(List<SalesMaster> tickets, ref List<SalesMaster> SM)
        {
              var VentasObligadas =   (from n in tickets
                                       where (n.Facturado || n.Tarjeta > 0)
                                       orderby Guid.NewGuid()
                                       select n).ToList();

              foreach (var element in VentasObligadas)
                  SM.Add(element);
            
        }

        private void VentasDeRelleno(List<SalesMaster> VentasMasterList, ref List<SalesMaster> Tickets, decimal meta)
        {
            bool caso1 = true;
            bool caso2 = false;
            bool caso3 = false;
            bool caso4 = false;
            int countVR1 = 0;
            int countVR2 = 0;
            int countVR3 = 0;
            int countVR4 = 0;
            const decimal MONTO_UNO = 40;
            const decimal MONTO_DOS = 80;
            const decimal MONTO_TRES = 120;
            decimal SumatoriaTotal = Tickets.Sum(n => n.Total);

            List<SalesMaster> VentasDeRelleno = (from n in VentasMasterList
                                                   where (!n.Facturado && n.Tarjeta == 0) 
                                                   orderby Guid.NewGuid()
                                                   select n).ToList();
             
            while (VentasDeRelleno.Count() > 0)
            {
                SalesMaster VR = new SalesMaster();

              if (caso1)
              {
                   VR = VentasDeRelleno.Where(n => n.Facturado == false && n.Tarjeta == 0 && n.Total <= MONTO_UNO).FirstOrDefault();
                   countVR1++;
                   caso1 = (countVR1 < 15);
                   caso2 = !caso1;
              }
                else if (caso2)
              {
                  VR = VentasDeRelleno.Where(n => n.Facturado == false && n.Tarjeta == 0 && n.Total > MONTO_UNO && n.Total <= MONTO_DOS).FirstOrDefault();
                  countVR2++;
                  caso2 = (countVR2 < 10);
                  caso3 = !caso2;
              }
                else if (caso3)
              {
                  VR = VentasDeRelleno.Where(n => n.Facturado == false && n.Tarjeta == 0 && n.Total > MONTO_DOS && n.Total <= MONTO_TRES).FirstOrDefault();
                  countVR3++;
                  caso3 = (countVR3 < 8);
                  caso4 = !caso3;
              }
              else if (caso4)
              {
                  VR = VentasDeRelleno.Where(n => n.Facturado == false && n.Tarjeta == 0 && n.Total > MONTO_TRES).FirstOrDefault();
                  countVR4++;
                  caso4 = (countVR4 < 2);
                  caso1 = !caso4;
                  if (caso1)
                  {
                      countVR1 = 0;
                      countVR2 = 0;
                      countVR3 = 0;
                      countVR4 = 0;
                  }
              }

              if (VR != null)
              {
                  if ((VR.Total + SumatoriaTotal) <= meta)
                  {
                      SumatoriaTotal = SumatoriaTotal + VR.Total;
                      Tickets.Add(VR);
                  }

                  VentasDeRelleno.Remove(VR);
              }
            }
 

        }
   
        private void CreateAuditFile(CutSales TEST)
        { 
        //_DataLayer.WriteSalesFiles
            string uno = "";
            string dos = "";
            const string  delimiter = " , ";
            const string NewLine = "\n";
            int count = 1;

            foreach (var Folios in TEST.tickets)
            {
                uno = (uno.Equals("") ? "" : uno + NewLine ) + count.ToString() + delimiter + delimiter /*fecha*/ + delimiter + delimiter + delimiter + delimiter + delimiter + delimiter + delimiter + delimiter + Folios.Efectivo + delimiter + Folios.Dolares + delimiter + Folios.TipoCambio + delimiter + Folios.Tarjeta + delimiter + delimiter + Folios.Total + delimiter + (Folios.Facturado ? "1" : "0"); 
                
                foreach (var tt in Folios.DetalleVentas)
                {
                    dos = (dos.Equals("") ? "" : dos + NewLine) + count.ToString() + delimiter + tt.NumArticulo + delimiter + tt.CantidadArticulos + delimiter + tt.PrecioTotal  + delimiter + tt.IDArticulo + delimiter + delimiter + delimiter + delimiter + delimiter + tt.TipoProducto; 
             
                }
                count++;
            }

           string FILENAME = TEST.tickets.Select(n => n.FileName).FirstOrDefault();

           _DataLayer.WriteSalesFiles(Parametros.settings.FolderCortes + "/" + FILENAME, uno);
           _DataLayer.WriteSalesFiles(Parametros.settings.FolderCortes + "/" + FILENAME.Replace("P","C"), dos);
        }
        #endregion

        #region Initialization

        public abstract class InitialProcess //Builder
        {
            public Parameters parametros { get; set; }
            public List<Users> usuarios { get; set; }
      
            public abstract void ReadDatosFiscales();
            public abstract void ReadMetas();
            public abstract void ReadArticulos();
            public abstract void ReadSettings();
            public abstract void ReadUsers();
        }
        public class InitialShop
        {
            public void LoadInitialData(InitialProcess loader)
            {
                loader.ReadDatosFiscales();
                loader.ReadMetas();
                loader.ReadArticulos();
                loader.ReadSettings();
                loader.ReadUsers();
            }

        }
        public class InitialLoader : InitialProcess
        {
            IFormatProvider culture = new CultureInfo("es-MX", true);
            private const char Delimiter = '~';
            DataLayer datalayer;

            public InitialLoader()
            {
                datalayer = new DataLayer();
                parametros = new Parameters();
                usuarios = new List<Users>();
            }

            public override void ReadDatosFiscales()
            {
                List<FiscalData> values = new List<FiscalData>();

                foreach (string rows in datalayer.ReadDatosFiscales())
                {
                    FiscalData value = new FiscalData();
                    string[] Columns = rows.Split(Delimiter);

                    value.Franquicia = Convert.ToInt32(Columns[0]);
                    value.Nombre = Columns[1];
                    value.NombreFiscal = Columns[2];
                    value.RFC = Columns[3];
                    value.Direccion = Columns[4];
                    value.Telefono = Columns[5];
                    value.Ciudad = Columns[6];
                    value.PagaIVA = Convert.ToBoolean(Columns[7]);
                    value.InicioOperaciones = DateTime.ParseExact(Columns[8], "dd/MM/yyyy", culture); 
                    values.Add(value);
                }
                parametros.DatosFiscales = values;
            }

            public override void ReadMetas()
            {
                List<DailyGoals> values = new List<DailyGoals>();

                foreach (string rows in datalayer.ReadMetas())
                {
                    DailyGoals value = new DailyGoals();
                    string[] Columns = rows.Split(Delimiter);

                    value.Franquicia = Convert.ToInt32(Columns[0]);
                    value.Lunes = Convert.ToDecimal(Columns[1]);
                    value.Martes = Convert.ToDecimal(Columns[2]);
                    value.Miercoles = Convert.ToDecimal(Columns[3]);
                    value.Jueves = Convert.ToDecimal(Columns[4]);
                    value.Viernes = Convert.ToDecimal(Columns[5]);
                    value.Sabado = Convert.ToDecimal(Columns[6]);
                    value.Domingo = Convert.ToDecimal(Columns[7]);

                    values.Add(value);
                }

                parametros.MetasDiarias = values;
            }

            public override void ReadArticulos()
            {
                List<Products> values = new List<Products>();

                foreach (string rows in datalayer.ReadArticulos())
                {
                    Products value = new Products();
                    string[] Columns = rows.Split(Delimiter);

                    value.ID = Convert.ToInt32(Columns[0]);
                    value.NombreArticuloCorto = Columns[1];
                    value.NombreArticuloLargo = Columns[2];

                    values.Add(value);
                }
                parametros.Productos = values;
            }

            public override void ReadSettings()
            {
                Settings values = new Settings();
                FtpParams ftpData = new FtpParams();

                string[] Columns = datalayer.ReadSettings().Split(Delimiter);

                values.IVA = Convert.ToDecimal(Columns[0]);
                values.PrinterName = Columns[1];
                
               // ftpData  =  Columns[2];  

                values.ftpParams = ftpData;
                values.PaginaWeb = Columns[3];
                values.GuardarZ = Convert.ToBoolean(Columns[4]);
                values.FolderCortes = Columns[5];
                

                parametros.settings = values;
            }
       
            public override void ReadUsers()
            {
                foreach (string rows in datalayer.ReadUsuarios())
                {
                    Users value = new Users();
                    string[] Columns = rows.Split(Delimiter);

                    value.ID = Convert.ToInt32(Columns[0]);
                    value.Nombre = Columns[1];
                    value.Usuario = Columns[2].ToUpper();
                    value.Contrasena = Columns[3];
                    value.Permisos = Columns[4];
                    usuarios.Add(value);
                }
            }

        }

        #endregion

    }

    #region classScope

    public class Parameters
    {
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        public List<int> FranquiciasSeleccionadas { get; set; }
        public int AuditType { get; set; }//Local or Download
        public Settings settings { get; set; }
        public List<FiscalData> DatosFiscales { get; set; }
        public List<DailyGoals> MetasDiarias { get; set; }
        public List<Products> Productos { get; set; }
    }

    public class Settings
    {
        public string PaginaWeb { get; set; }
        public string PrinterName { get; set; }
        public decimal IVA { get; set; }
        public FtpParams ftpParams { get; set; }
        public bool GuardarZ { get; set; }
        public string FolderCortes { get; set; }
    }
  
    public class FtpParams
    {
        public string FTPHost { get; set; }
        public string userName { get; set; }
        public string password { get; set; }
        public string downloadPath { get; set; }
    }

    public class FilesToProcess
    {
        public string FileName { get; set; }
        public int Franquicia { get; set; }
        public bool Exist { get; set; }
        public DateTime Date { get; set; }
    }

    public class DailyGoals
    {
        public int Franquicia { get; set; }
        public decimal Lunes { get; set; }
        public decimal Martes { get; set; }
        public decimal Miercoles { get; set; }
        public decimal Jueves { get; set; }
        public decimal Viernes { get; set; }
        public decimal Sabado { get; set; }
        public decimal Domingo { get; set; }
    }
   
    public class FiscalData
    {
        public int Franquicia { get; set; }
        public string Nombre { get; set; }
        public string NombreFiscal { get; set; }
        public string RFC { get; set; }
        public string Direccion { get; set; }
        public string Ciudad { get; set; }
        public string Telefono { get; set; }
        public DateTime InicioOperaciones { get; set; }
        public bool PagaIVA { get; set; }
    }

    public class Products
    {
        public int ID { get; set; }
        public string NombreArticuloCorto { get; set; }
        public string NombreArticuloLargo { get; set; }
    }

    public class CutSales
    {
        public int NumCorte { get; set; }
        public DateTime Fecha { get; set; }
        public decimal Meta { get; set; }  
        public int Franquicia { get; set; }
        public List<SalesMaster> tickets { get; set; }
        public decimal Alimentos { get; set; }
        public decimal Bebidas { get; set; }
        public decimal Extra { get; set; }
        public decimal Iva { get; set; }
        public decimal SubTotal { get; set; }
        public decimal Total { get; set; }
    }

    public class SalesMaster
    {
        public int Folio { get; set; }
        public int Franquicia { get; set; }
        public DateTime Fecha { get; set; }
        public bool Exist { get; set; }
        public bool Facturado { get; set; }
        public bool Cortesia { get; set; }
        public decimal Efectivo { get; set; }
        public decimal Dolares { get; set; }
        public decimal TipoCambio { get; set; }
        public decimal Tarjeta { get; set; }
        public decimal Alimentos { get; set; }
        public decimal Bebidas { get; set; }
        public decimal Extra { get; set; }
        public decimal Iva { get; set; }
        public decimal SubTotal { get; set; }
        public decimal Total { get; set; }
        public string FileName { get; set; }
        public List<SalesDetail> DetalleVentas { get; set; }
    }

    public class SalesDetail
    {
        public int Folio { get; set; }
        public DateTime Fecha { get; set; }
        public int franquicia { get; set; }
        public int NumArticulo { get; set; }
        public int IDArticulo { get; set; }
        public int CantidadArticulos { get; set; }
        public string NombreArticulo { get; set; }
        public decimal PrecioUnitario { get; set; }
        public decimal PrecioTotal { get; set; }
        public int TipoProducto { get; set; } // 1=Extras 2=Bebidas 3= Alimentos 
        public int Descuento { get; set; }
        public string Cajero { get; set; } 
    }

    public class Users 
    {
        public int ID { get; set; }
        public string Nombre { get; set; }
        public string Usuario { get; set; }
        public string Contrasena { get; set; }
        public string Permisos { get; set; }
    }
#endregion



}
